home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / LISP Related / U. Mass AI & LISP Tools / MODULES / SM / SMEDIT.lisp < prev   
Encoding:
Text File  |  1990-06-25  |  77.2 KB  |  1,638 lines  |  [TEXT/CCL ]

  1. ; (c) Copyright 1990 by University of Massachusetts. All rights reserved.
  2. ; This software was conceived, designed, and written by Dan Suthers 
  3. ; while supported by the National Science Foundation under grant number
  4. ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
  5. ; CA.  Partial support was also received from the Office of Naval Research
  6. ; under a University Research Initiative Grant, contract N00014-86-K-0764.
  7. ; Mr. Suthers created this software under his own initiative while in an 
  8. ; academic relationship with the University of Massachusetts.  The above
  9. ; copyright notice was a condition placed by University lawyers on approval
  10. ; of distribution of this software by Apple Computer, and is not meant to
  11. ; imply that this software was created in an employment or "work for hire"
  12. ; relationship between the University and Mr. Suthers.
  13. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14. ; File:         SMEDIT.LISP
  15. ; Author:       Dan Suthers
  16. ; Created:      01-Jan-88 22:55:00
  17. ; Modified:     22-Jun-90 02:13:23 (Dan Suthers)
  18. ; Language:     LISP
  19. ; Package:      SM
  20. ;
  21. ; Description:  Frame browser and editor for SM (see documentation below).
  22. ;               CORAL ALLEGRO COMMON LISP VERSION FOR THE MACINTOSH.
  23. ;
  24. ; (c) Copyright 1988, by Daniel D. Suthers
  25. ;                        Department of Computer and Information Science
  26. ;                        University of Massachusetts
  27. ;                        Amherst, Massachusetts 01003
  28. ;
  29. ; This software was conceived, designed, and written by Dan Suthers 
  30. ; while supported by the National Science Foundation under grant number
  31. ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
  32. ; CA.  Partial support was also received from the Office of Naval Research
  33. ; under a University Research Initiative Grant, contract N00014-86-K-0764.
  34. ; I wish to acknowledge the generous support of Beverly Woolf, who obtained 
  35. ; the above grants and encouraged me to pursue my own research interests in
  36. ; her lab.  This work would not have been possible without the resources and
  37. ; stimulating environment of the Computer and Information Science department.
  38. ;
  39. ; Permission to use, modify, and distribute this software is granted subject 
  40. ; to the following restrictions and understandings:
  41. ; 1. The file header, including this notice, shall be retained, and may be
  42. ;    extended to include documentation of modifications to the software.
  43. ; 2. This material is for nonprofit educational and research purposes only.
  44. ;    Users are requested, but not required, to inform Mr. Suthers of any 
  45. ;    noteworthy uses of this software.
  46. ; 3. Mr. Suthers and the University of Massachusetts make no warrantee or
  47. ;    representation that the operation of this software will be error free,
  48. ;    and are under no obligation to provide any services.
  49. ; 4. Any user of such software agrees to indemnify and hold harmless Mr.
  50. ;    Suthers and the University of Massachusetts from all claims arising 
  51. ;    out of the use or misuse of this software, or arising out of any 
  52. ;    accident, injury, or damage whatsoever, and from all costs, counsel
  53. ;    fees, and liabilities incurred in or about any such claim, action, or
  54. ;    proceeding brought thereon.
  55. ; 5. All materials and reports developed as a consequence of the use of 
  56. ;    this software shall duly acknowledge such use, in accordance with
  57. ;    the usual standards of acknowledging credit in academic research.
  58. ;
  59. ; Status:       Tested and presumed usable 30-Jan-90
  60. ;
  61. ; Changes:      
  62. ;
  63. ;   31-Jan-88 Using :summary and :brief styles as appropriate; default path 
  64. ;     and extension for instance files. Edit-struct-actions associates types 
  65. ;     with (lambda (instance editor) ...) to alter edit buffer.
  66. ;   03-Feb-88 Make new instance names in same package as type.
  67. ;   04-Feb-88 Edit-struct makes windows wide enough for titles if the title is 
  68. ;     larger than the macro columns.
  69. ;   10-Feb-88 Selection of instance no longer pops up previous edit window: this
  70. ;     was annoying.  Now must select edit.  Also added choose-file-dialogs.
  71. ;   11-Feb-88 Moving buttons around.  Selection of instance reminds you if edit 
  72. ;     window is up.
  73. ;   26-Feb-88 Made it machine-independent with file-I/O on those machines not 
  74. ;     supporting windows.
  75. ;   19-Apr-88 Converted to SM (rename of KR0); also renamed edit-struct -> edits.
  76. ;   10-May-88 Updating for new SM.
  77. ;   20-Jun-88 Displays type information when type selected.
  78. ;   29-Jun-88 More save-type and save-instance options now user selectable; 
  79. ;     improvements in browser display.
  80. ;   03-Jul-88 Inspect and Style buttons added.  Using new COPIES for copying.
  81. ;     Small browser reorganized to have Inspect button.
  82. ;   13-Jul-88 Updated for new SM slots and type editing capabilities.
  83. ;   19-Jul-88 Added Go To button for following links via slots.  Also
  84. ;     each browser has its own prints style. 
  85. ;   24-Jul-88 Flush Freelist on menu.  Fred windows no longer scratch, but
  86. ;     destroy-sm-editor-windows-of-type ignores mod-flag. Added close button.
  87. ;   30-Jul-88 Edit Slot added, close button moved to menu.
  88. ;   25-Oct-88 Pretty printing type definitions when editing them.  When 
  89. ;     saving instances all instances of a type from the menu, edits windows
  90. ;     go away when done.  This lets them serve as indicators when there is
  91. ;     in-memory stuff to save.
  92. ;   01-Nov-88 When creating a browser, you can specify the title and which
  93. ;     classes are displayed.  EDITS now refers to type option :after-edit
  94. ;     to get its edit actions.  Browser no longer sorts instance names,
  95. ;     since user will have specified :sort-instances if this is important.
  96. ;   11-Nov-88 Fixed error when deleting last instance of a type in browser.
  97. ;   13-Nov-88 :Before-edit option added.
  98. ;   16-Nov-88 SAVE-TYPE-PARAMETER-DIALOGUE supports added :append option.
  99. ;     Order of returned values changed to be consistent with menu ordering.
  100. ;   01-Dec-88 DESTROY-SM-EDITOR-WINDOWS-OF-TYPE now has :ask-user option.
  101. ;   17-Dec-88 EDITS now puts up windows in package specified by type option 
  102. ;    :edit-in-package, or in that of the instance name (instead of the type).
  103. ;    NEW-INSTANCE-NAME now uses UTILS:UNIQUE-SYMBOL.
  104. ;  31-Dec-88 Updated warning due to change to COPIES, which now copies conses.
  105. ;  11-Jan-88 Menu Flush Freelist now changed to Freelist Manager
  106. ;  14-Sep-89 Fixed extra quote error in New Type template, and allowing
  107. ;    new types on load-type menu option. -- DS
  108. ;  25-Oct-89 Exporting find-editor-window, useful elsewhere. -- DS
  109. ;  29-Oct-89 SAVE-TYPE-PARAMETER-DIALOGUE defaults inclusion of type
  110. ;    definition according to type option :save-type-definition.
  111. ;    Save Type menu option destroys Edits windows when done.  -- DS
  112. ;  07-Nov-89 Wrote menu-item-update for warn of redefinitions menu item.
  113. ;  30-Jan-90 Update for version 1.3.1: :default-button now in button items.
  114. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  115. ; CORAL ALLEGRO COMMON LISP VERSION:
  116. ;
  117. ; MENU: 
  118. ;
  119. ; A menu is created which includes options to:
  120. ; - Activate BROWSE-STRUCT (described below) for mouse-driven browsing,
  121. ; - Toggle *warn-of-redefinitions*.
  122. ; - Close all EDITS windows of a specified type.
  123. ; - Edit the type definition.
  124. ; - Invoke SM operations of RESET-TYPE, DESTROY-TYPE,
  125. ;   RESET-ALL-TYPES, DESTROY-ALL-TYPES, LOAD-TYPE,
  126. ;   and SAVE-TYPE.
  127. ;
  128. ; BROWSE-STRUCT:
  129. ;
  130. ; The primary means of accessing SM instances, this creates a window
  131. ; with two scrollable menus for choice of type and instance, a display 
  132. ; window for viewing pretty printed representations of instances, and 
  133. ; various buttons for operating on instances.  
  134. ; When a TYPE is selected in the type menu, all the instances of the 
  135. ; type are listed in the instance scrollable menu.
  136. ; When an INSTANCE is selected, it is displayed in the display window. 
  137. ; If an editor window exists for the object, a message notes this fact.
  138. ; Note that while the display window is Macintosh "editable text", and 
  139. ; the user may alter the displayed text, this has no effect on the 
  140. ; instance.  I used the editable text dialog item simply because it 
  141. ; draws a box around the text, and use of arrow keys allows the user to
  142. ; see text which is too big to fit in the box.  Potential confusion about
  143. ; whether editing this representation has an effect may be averted by 
  144. ; printing only non-readable forms in this window.
  145. ;
  146. ; The EDIT button creates a Fred window with the macro representation
  147. ; of an instance, such that the buffer may be evaluated after editing 
  148. ; to redefine the instance.  If such a window already exists, it is 
  149. ; selected.  Type options :before-edit and :after-edit are checked to
  150. ; determine what forms should be inserted in the editor buffer before
  151. ; and after the instance representation, respectively.  These options
  152. ; should be lambdas of one argument to be given the instance name.
  153. ;
  154. ; SLOT-EDIT puts up an editor buffer with a form that lets you SETF
  155. ; the value of one slot of the instance after editing.  This is useful
  156. ; for altering values of :COMPUTED slots (which don't appear in EDITS
  157. ; buffers).
  158. ;
  159. ; The COPY button makes a copy of the instance under a new instance name
  160. ; provided by the user.  It uses COPIES, so read-only slots are copied. The 
  161. ; macro representation of the instance is brought up in an edit window.
  162. ;
  163. ; NEW creates a new instance with default slot values, bringing up its
  164. ; macro representation in an edit window.  The user is asked for a name.
  165. ;
  166. ; GOTO allows one to browse through a network of instances.  It asks you what
  167. ; slot of the current instance contains the name(s) of other instances.  If 
  168. ; the value of this slot is a symbol, it is assumed to be the name of another
  169. ; instance of the same type, and this instance becomes the current instance
  170. ; and is displayed in the browser.  If the slot contains a list, a menu is put
  171. ; up allowing you to select an element of the list.  Processing of the selected
  172. ; element depends on whether it is a symbol or a list, and is as just stated.
  173. ;
  174. ; STYLE allows you to select which PRINTS style to use to display instances in
  175. ; the current browser.
  176. ;
  177. ; INSPECT invokes the inspector on the currently selected object.  If a type
  178. ; is selected but no instance, the structure-type structure (which records
  179. ; definitional information) for that type is inspected.  If an instance is
  180. ; selected, its structure is inspected.
  181. ;
  182. ; The DESTROY button destroys the selected instance (using destroys).
  183. ;
  184. ; Design Principles:
  185. ;
  186. ; o Buttons are only enabled when they are applicable and safe:
  187. ;   - Style is always enabled.
  188. ;   - New and Inspect are enabled only when a type is selected.
  189. ;   - Edit, Slot-Edit, Copy, Goto, and Destroy are enabled only when an
  190. ;     instance is selected.
  191. ;   Exception is due to a fault in the dialog sequence items: when a null
  192. ;   cell is selected, no action is executed, so I cannot deselect the buttons
  193. ;   when the user deselects a type or instance.  To avoid problems, the 
  194. ;   buttons watch for null type or instance.
  195. ;
  196. ; o Duplicate or inconsistent displays are avoided.
  197. ;   - Re-editing an object causes its existing edit window to come up.
  198. ;   - Selecting an object for viewing results in a reminder that the 
  199. ;     object is in an edit window, printed before the viewing representation.
  200. ;   - If a menu action makes a change which invalidates the structure browser
  201. ;     display, such as resetting or destroying a type, all existing structure
  202. ;     browsers are destroyed.
  203. ;   - If a type is destroyed from the menu, all windows displaying instances 
  204. ;     of that type are also destroyed.
  205. ;   - If a single instance is destroyed, and an edit window exists for that
  206. ;     instance, the window is destroyed.
  207. ;   An exception: after SAVE-TYPE, all instance windows for the type are destroyed 
  208. ;   without confirmation.  This allows instance windows to act as a "lock" against
  209. ;   leaving lisp without saving the type, which is "unlocked" when it is saved. 
  210. ;   The only danger is that editing in unevaluated buffers will be lost.
  211. ;
  212. ; o The user has an opportunity to abort whenever an action will irretrievably
  213. ;   destroy information.
  214. ;   - Instance windows created by EDITS and type definition editing windows are
  215. ;     not scratch windows, so Allegro puts up a confirmation dialogue when they
  216. ;     are destroyed.
  217. ;   - Confirmation is requested for DESTROYS, RESET-TYPE, etc.
  218. ;
  219. ; EDITS:
  220. ; This has syntax similar to sm:prints (without the stream or style),
  221. ; and creates a window with an evaluatable macro representation to edit.
  222. ; It is used by browse-struct, and may be useful for other code.  See its
  223. ; documentation if needed.
  224. ;
  225. ; The :BEFORE-EDIT and :AFTER-EDIT type options are handles for clients which 
  226. ; may wish to execute instance-processing forms before or after editing.  To 
  227. ; use it, record under the :before-edit or :after-edit type option a lambda 
  228. ; form which takes the instance name as argument and performs the actions. 
  229. ; In the CCL version of SMEDIT, this is accomplished by inserting a funcall
  230. ; of the :before-edit and :after-edit forms into the beginning and end, 
  231. ; respectively, of the buffer created by EDITS.
  232. ;
  233. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  234. ;
  235. ; UNFIXED GLITCHES & POSSIBLE IMPROVEMENTS:
  236. ;
  237. ; If an instance has a name of NIL, every time it is selected the browser
  238. ; will behave as if it just discovered that there is no selected instance.
  239. ; This is because tests for whether selected-instance is nil trigger calls
  240. ; to no-instance-selected-handler.  Could probably work around this with
  241. ; multiple value returns (2nd value telling if this IS an instance name).
  242. ;
  243. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  244.  
  245. (in-package :SM)
  246.  
  247. (require :MISC    )     ; for unique-symbol
  248. (require :DIALOGUE)
  249.  
  250. (export '(
  251.           *sm-menu*
  252.           browse-structs
  253.           destroy-structure-browsers
  254.           destroy-sm-editor-windows-of-type
  255.           edits
  256.           find-editor-window
  257.           next-window-position
  258.           new-instance-name
  259.           save-type-parameter-dialogue
  260.           ))
  261.  
  262. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  263.  
  264. (defconstant *EDITOR-WINDOW-FONT* '("monaco" 9))
  265.  
  266. (defconstant *EDITOR-WINDOW-FONT-HEIGHT*
  267.   (multiple-value-bind
  268.     (a d w l) 
  269.     (ccl:font-info *editor-window-font*)
  270.     (declare (ignore w l))
  271.     (+ a d 2)))
  272.  
  273. (defvar *STRUCTURE-BROWSERS* nil)    ; known browsers
  274.  
  275. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  276. ;;;
  277. ;;;                            HELPER MACROS
  278. ;;; 
  279. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  280.  
  281. ;;; The following macros will make more sense after reading BROWSE-STRUCT.
  282. ;;; They are macros instead of functions to be in the active object's 
  283. ;;; lexical environment.  They are only needed at compile time
  284.  
  285. (eval-when (compile eval)
  286.   
  287.   (defmacro NO-TYPE-SELECTED-HANDLER ()
  288.     '(progn
  289.        ;; Empty the instances list
  290.        (ccl:ask
  291.         (third (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  292.         (ccl:set-table-sequence nil))
  293.        ;; Update display.
  294.        (ccl:ask 
  295.         (fourth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  296.         (ccl:set-dialog-item-text "No Type selected."))
  297.        ;; Ask buttons to disable themselves.
  298.        (ccl:ask ; edit
  299.         (fifth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  300.         (ccl:dialog-item-disable))
  301.        (ccl:ask ; destroy
  302.         (sixth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  303.         (ccl:dialog-item-disable))
  304.        (ccl:ask ; copy
  305.         (seventh (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  306.         (ccl:dialog-item-disable))
  307.        (ccl:ask ; new
  308.         (eighth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  309.         (ccl:dialog-item-disable))
  310.        (ccl:ask ; goto
  311.         (ninth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  312.         (ccl:dialog-item-disable))
  313.        (ccl:ask ; inspect
  314.         (tenth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  315.         (ccl:dialog-item-disable))
  316.        (ccl:ask ; slot edit
  317.         (nth 11 (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  318.         (ccl:dialog-item-disable))))
  319.   
  320.   (defmacro NO-INSTANCE-SELECTED-HANDLER (update-display?)
  321.     `(progn 
  322.        ;; Update display if requested.
  323.        ,@(if update-display?
  324.            '((ccl:ask
  325.               (fourth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  326.               (ccl:set-dialog-item-text "No instance selected."))))
  327.        ;; Ask buttons which require instance to disable.
  328.        (ccl:ask ; edit
  329.         (fifth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  330.         (ccl:dialog-item-disable))
  331.        (ccl:ask ; destroy
  332.         (sixth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  333.         (ccl:dialog-item-disable))
  334.        (ccl:ask ; copy
  335.         (seventh (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  336.         (ccl:dialog-item-disable))
  337.        (ccl:ask ; go to
  338.         (ninth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  339.         (ccl:dialog-item-disable))
  340.        (ccl:ask ; slot edit
  341.         (nth 11 (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  342.         (ccl:dialog-item-disable))))
  343.  
  344.   ) ; end of eval-when
  345.  
  346. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  347. ;;;
  348. ;;;                             BROWSER
  349. ;;; 
  350. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  351.  
  352. (defun BROWSE-STRUCTS (&key (small nil) 
  353.                             (types (structure-types)) 
  354.                             (title "Structure Browser "))
  355.   "browse-structs &optional <small>                                 [Function]
  356.   Creates and returns a permanent structure browsing window, which
  357.   includes menus for selection of type and instance, displays the 
  358.   selected instance, and allows editing, deletion, copying, and 
  359.   creation operations.  Non-nil optional argument makes small browser."
  360.   (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  361.   (check-type types list)
  362.   (check-type title string)
  363.   (assert (every #'(lambda (ty) (member ty (structure-types))) types) (types)
  364.           "Types argument must be a list of structure type names.")
  365.  
  366.   ;; Dialog items need to refer to each other recursively.  They
  367.   ;; do so by referencing the > position < of the desired item in
  368.   ;; the dialog-items list of the dialog created.  The let* is so
  369.   ;; the browser dialog can refer back to the dialog items.
  370.   
  371.   (let*
  372.     (
  373.      (*prints-style* (if small :brief :summary))
  374.      
  375.      ;; Labels on the two menus.
  376.      (labels 
  377.        (ccl:oneof 
  378.         ccl:*static-text-dialog-item*
  379.         :dialog-item-font '("chicago" 12)
  380.         :dialog-item-text
  381.         (if small 
  382.           "  Structure Type                    Instances"
  383.           "  Structure Type                               Instances")))
  384.      
  385.      ;; Table to select structure type from.
  386.      (type-menu 
  387.       (ccl:oneof
  388.        ccl:*sequence-dialog-item*
  389.        :dialog-item-size (if small (ccl:make-point 150 140) 
  390.                              (ccl:make-point 200 140))
  391.        :dialog-item-position (ccl:make-point 6 22)
  392.        :table-vscrollp t
  393.        :table-hscrollp nil
  394.        :visible-dimensions (ccl:make-point 1 5)
  395.        :cell-size (if small (ccl:make-point 150 16)
  396.                       (ccl:make-point 200 16))
  397.        :table-sequence 
  398.        ;; Sort this because user may have given unsorted list.
  399.        (sort (copy-list types)
  400.              #'(lambda (x y) 
  401.                  (string< (symbol-name x) (symbol-name y))))
  402.        :sequence-order :vertical
  403.        :dialog-item-action 
  404.        #'(lambda ()
  405.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  406.            (let ((selected-type 
  407.                   (ccl:cell-contents (car (ccl:selected-cells)))))
  408.              ;; Display information about the type.
  409.              (ccl:ask 
  410.               (fourth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  411.               (ccl:set-dialog-item-text
  412.                (if small
  413.                  (remove #\newline
  414.                          (or (type-info selected-type :comments)
  415.                              "Use large structure browser for information on this type 
  416. and its slot definitions. Alternately, inspect the type."))
  417.                  ;; This string takes some grinding, so do it only
  418.                  ;; once per type per session, and save.
  419.                  (or (get selected-type '$browser-doc-string$)
  420.                      (setf (get selected-type '$browser-doc-string$)
  421.                            (let ((*print-pretty* T))
  422.                              (flet ((deconser (a+b) (list (car a+b) (cdr a+b))))
  423.                                (format 
  424.                                 nil 
  425.                                 "~:@(---------- Structure Type ~S ----------~)~
  426.                                  ~%UNCOMPUTED SLOTS: ~A~
  427.                                  ~%COMPUTED SLOTS:   ~A~
  428.                                  ~%READ ONLY SLOTS:  ~A~
  429.                                  ~%REUSABLE: ~A; REPRESENTATION: ~A; INITIAL-OFFSET: ~A; NAMED: ~A~
  430.                                  ~%TYPE-INFO:     ~S~
  431.                                  ~%SLOT INFO:     ~{~&  [~:@(~A:~) ~S]~}~
  432.                                  ~%SLOT DEFAULTS: ~{~&  [~:@(~A:~) ~S]~}~
  433.                                  ~%SLOT TYPES:    ~{~&  [~:@(~A:~) ~S]~}"
  434.                                 selected-type
  435.                                 (uncomputed-slots selected-type)
  436.                                 (computed-slots selected-type)
  437.                                 (read-only-slots selected-type)
  438.                                 (reusable selected-type)
  439.                                 (representation selected-type)
  440.                                 (initial-offset selected-type)
  441.                                 (named selected-type)
  442.                                 (type-info selected-type)
  443.                                 ;; Extra work needed since format can't handle dots.
  444.                                 (mapcan #'deconser (slot-info selected-type))
  445.                                 (mapcan #'deconser (slot-defaults selected-type))
  446.                                 (mapcan #'deconser (slot-types selected-type))))))))))
  447.              ;; List instances in instance menu.
  448.              (ccl:ask
  449.               (third (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  450.               (ccl:set-table-sequence (instances selected-type)))
  451.              (no-instance-selected-handler nil)
  452.              ;; Enable new and inspect buttons
  453.              (ccl:ask ; new
  454.               (eighth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  455.               (ccl:dialog-item-enable))
  456.              (ccl:ask ; inspect
  457.               (tenth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  458.               (ccl:dialog-item-enable))))))
  459.      
  460.      ;; Table to select instance from.
  461.      (instance-menu 
  462.       (ccl:oneof
  463.        ccl:*sequence-dialog-item*
  464.        :dialog-item-size (if small (ccl:make-point 150 140) 
  465.                              (ccl:make-point 200 140))
  466.        :dialog-item-position (if small (ccl:make-point 180 22) 
  467.                                  (ccl:make-point 230 22))
  468.        :table-vscrollp t
  469.        :table-hscrollp nil
  470.        :visible-dimensions (ccl:make-point 1 5)
  471.        :cell-size (if small (ccl:make-point 150 16) 
  472.                       (ccl:make-point 200 16))
  473.        :table-sequence nil
  474.        :sequence-order :vertical
  475.        :dialog-item-action 
  476.        #'(lambda ()
  477.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  478.            (let* ((selected-instance
  479.                    (ccl:cell-contents (car (ccl:selected-cells))))
  480.                   (selected-type
  481.                    (ccl:ask type-menu
  482.                             (if (ccl:selected-cells)
  483.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  484.                   (title nil) (window nil) (representation nil))
  485.              (if (null selected-type)
  486.                (no-type-selected-handler)
  487.                ;; Type is selected, process instance.
  488.                (progn
  489.                  (setf title (prints selected-type selected-instance
  490.                                      :style :name :stream nil)
  491.                        window (find-editor-window title)
  492.                        representation
  493.                        (prints selected-type selected-instance
  494.                                :style *prints-style* :stream nil))
  495.                  ;; Display in non-edit window in browser, with reminder
  496.                  ;; if an edit window is up.
  497.                  (ccl:ask
  498.                   (fourth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  499.                   (ccl:set-dialog-item-text
  500.                    (if window
  501.                      (format nil "***** ~A in Edit window *****~%~A"
  502.                              title representation)
  503.                      representation)))
  504.                  ;; Enable instance processing buttons.
  505.                  (ccl:ask ; edit
  506.                   (fifth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  507.                   (ccl:dialog-item-enable))
  508.                  (ccl:ask ; destroy 
  509.                   (sixth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  510.                   (ccl:dialog-item-enable))
  511.                  (ccl:ask ; copy
  512.                   (seventh (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  513.                   (ccl:dialog-item-enable))
  514.                  (ccl:ask ; go to 
  515.                   (ninth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  516.                   (ccl:dialog-item-enable))
  517.                  (ccl:ask ; slot edit
  518.                   (nth 11 (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  519.                   (ccl:dialog-item-enable))))))))
  520.  
  521.      ;; Region in which printed representation of instance is displayed.
  522.      (display 
  523.       (ccl:oneof 
  524.        ccl:*editable-text-dialog-item*
  525.        :dialog-item-size (if small (ccl:make-point 335 85) 
  526.                              (ccl:make-point 590 200))
  527.        :dialog-item-position (ccl:make-point 8 114)
  528.        :dialog-item-font '("monaco" 9)
  529.        :dialog-item-text "Nothing Selected."
  530.        :allow-returns t))
  531.      
  532.      ;; Button for creating Fred window to edit selected instance.
  533.      ;; Disabled unless an instance is selected.
  534.      (edit-button 
  535.       (ccl:oneof 
  536.        ccl:*button-dialog-item*
  537.        :dialog-item-text " Edit "
  538.        :dialog-item-position (if small (ccl:make-point 362 11)
  539.                                  (ccl:make-point 467 11))
  540.        :dialog-item-enabled-p nil
  541.        :dialog-item-action
  542.        #'(lambda ()
  543.            (let ((selected-instance
  544.                   (ccl:ask instance-menu
  545.                            (if (ccl:selected-cells)
  546.                              (ccl:cell-contents (car (ccl:selected-cells))))))
  547.                  (selected-type
  548.                   (ccl:ask type-menu
  549.                            (if (ccl:selected-cells)
  550.                              (ccl:cell-contents (car (ccl:selected-cells)))))))
  551.              (cond 
  552.               ((null selected-type) (no-type-selected-handler))
  553.               ((null selected-instance) (no-instance-selected-handler T))
  554.               ((EDITS selected-type selected-instance)
  555.                ;; Update display.
  556.                (ccl:ask display
  557.                         (ccl:set-dialog-item-text 
  558.                          (format nil "~A in edit window."
  559.                                  (prints selected-type selected-instance
  560.                                          :style :name :stream nil))))))))))
  561.  
  562.      ;; Button for destroying the instance selected.
  563.      (destroy-button
  564.       (ccl:oneof
  565.        ccl:*button-dialog-item*
  566.        :dialog-item-text "Destroy"
  567.        :dialog-item-position (if small (ccl:make-point 353 186)
  568.                                  (ccl:make-point 530 86))
  569.        :dialog-item-enabled-p nil
  570.        :dialog-item-action
  571.        #'(lambda ()
  572.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  573.            (let* ((selected-instance
  574.                    (ccl:ask instance-menu
  575.                             (if (ccl:selected-cells)
  576.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  577.                   (selected-type
  578.                    (ccl:ask type-menu
  579.                             (if (ccl:selected-cells)
  580.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  581.                   (title nil))
  582.              (cond 
  583.               ((null selected-type)     (no-type-selected-handler))
  584.               ((null selected-instance) (no-instance-selected-handler t))
  585.               (t 
  586.                ;; Get name of destroyed thing, before destroying.
  587.                (setf title
  588.                      (prints selected-type selected-instance
  589.                              :style :name :stream nil))
  590.                (if (wind:y-or-n-dialogue 
  591.                     (format nil "Destroy structure instance~&~A?" title))
  592.                  (progn
  593.                    (destroys selected-type selected-instance)
  594.                    ;; Update instance list and display.
  595.                    (ccl:ask instance-menu
  596.                             (ccl:cell-deselect (first (ccl:selected-cells)))
  597.                             (ccl:set-table-sequence (instances selected-type))
  598.                             (if (instances selected-type)
  599.                               (ccl:scroll-to-cell (ccl:index-to-cell 0))))
  600.                    (ccl:ask display
  601.                             (ccl:set-dialog-item-text 
  602.                              (format nil "~A destroyed." title)))
  603.                    ;; Disable buttons requiring instance.
  604.                    (ccl:ask ; edit
  605.                     (fifth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  606.                     (ccl:dialog-item-disable))
  607.                    (ccl:ask ; destroy 
  608.                     (sixth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  609.                     (ccl:dialog-item-disable))
  610.                    (ccl:ask ; copy
  611.                     (seventh (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  612.                     (ccl:dialog-item-disable))
  613.                    (ccl:ask ; go to 
  614.                     (ninth (ccl:ask ccl:my-dialog (ccl:dialog-items)))
  615.                     (ccl:dialog-item-disable))
  616.                    ;; Destroy window if it exists.
  617.                    (let ((ew (find-editor-window title)))
  618.                      (if ew
  619.                        (ccl:ask ew (ccl:window-close))))))))))))
  620.      
  621.      ;; Button for copying instance into new instance which is 
  622.      ;; brought up in Fred window (for copy + edit paradigm).
  623.      (copy-button
  624.       (ccl:oneof 
  625.        ccl:*button-dialog-item*
  626.        :dialog-item-text " Copy "
  627.        :dialog-item-position (if small (ccl:make-point 358 61)
  628.                                  (ccl:make-point 464 61))
  629.        :dialog-item-enabled-p nil
  630.        :dialog-item-action
  631.        #'(lambda ()
  632.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  633.            (let* ((selected-instance
  634.                    (ccl:ask instance-menu
  635.                             (if (ccl:selected-cells)
  636.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  637.                   (selected-type
  638.                    (ccl:ask type-menu
  639.                             (if (ccl:selected-cells)
  640.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  641.                   (new-instance nil))
  642.              (cond 
  643.               ((null selected-type)     (no-type-selected-handler))
  644.               ((null selected-instance) (no-instance-selected-handler t))
  645.               ;; Nil is returned from new-instance-name if user cancels.
  646.               ((setf new-instance (new-instance-name selected-type))
  647.                (copies selected-type selected-instance new-instance :copy-tree t)
  648.                ;; Write important warning into browser.
  649.                (ccl:ask display
  650.                         (ccl:set-dialog-item-text 
  651.                          "WARNING: Only slot values which are conses are copied."))
  652.                ;; Update menu and edit so user can fill in slots.
  653.                (ccl:ask instance-menu
  654.                         (ccl:cell-deselect (first (ccl:selected-cells)))
  655.                         (ccl:set-table-sequence (instances selected-type))
  656.                         (ccl:scroll-to-cell (ccl:index-to-cell 0)) ; new instance
  657.                         (ccl:cell-select (ccl:index-to-cell 0)))
  658.                (edits selected-type new-instance)))))))
  659.      
  660.      ;; Button to create a new instance of selected type.
  661.      ;; (Instance need not be selected.)
  662.      (new-button 
  663.       (ccl:oneof 
  664.        ccl:*button-dialog-item*
  665.        :dialog-item-text " New "
  666.        :dialog-item-position (if small (ccl:make-point 360 86)
  667.                                  (ccl:make-point 466 86))
  668.        :dialog-item-enabled-p nil
  669.        :dialog-item-action
  670.        #'(lambda ()
  671.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  672.            (let* ((selected-type
  673.                    (ccl:ask type-menu
  674.                             (if (ccl:selected-cells)
  675.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  676.                   (new-instance nil))
  677.              (cond 
  678.               ((null selected-type) (no-type-selected-handler))
  679.               ((setf new-instance (new-instance-name selected-type))
  680.                ;; Have a new name: create default instance (default
  681.                ;; values provided by the <type> macro).
  682.                (funcall (creator selected-type) new-instance)
  683.                ;; Ask instance item to re-list instances
  684.                (ccl:ask instance-menu
  685.                         (if (ccl:selected-cells)
  686.                           (ccl:cell-deselect (first (ccl:selected-cells))))
  687.                         (ccl:set-table-sequence (instances selected-type))
  688.                         (ccl:scroll-to-cell (ccl:index-to-cell 0)) ; new instance
  689.                         (ccl:cell-select (ccl:index-to-cell 0)))
  690.                ;; Put up edit window.  There should not be existing window.
  691.                (edits selected-type new-instance)
  692.                (ccl:ask display
  693.                         (ccl:set-dialog-item-text 
  694.                          (format nil "New Instance ~S is in edit window."
  695.                                  new-instance))))
  696.               ((ccl:ed-beep)))))))
  697.  
  698.      ;; Button for browsing a structure named in a slot of the selected structure.
  699.      (go-to-button
  700.       (ccl:oneof 
  701.        ccl:*button-dialog-item*
  702.        :dialog-item-text " Go To "
  703.        :dialog-item-position (if small (ccl:make-point 358 111)
  704.                                  (ccl:make-point 534 11))
  705.        :dialog-item-enabled-p nil
  706.        :dialog-item-action
  707.        #'(lambda ()
  708.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  709.            (let* ((selected-instance
  710.                    (ccl:ask instance-menu
  711.                             (if (ccl:selected-cells)
  712.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  713.                   (selected-type
  714.                    (ccl:ask type-menu
  715.                             (if (ccl:selected-cells)
  716.                               (ccl:cell-contents (car (ccl:selected-cells))))))
  717.                   (instance-structure nil) (slots->values nil) 
  718.                   (selected-slot nil) (slot-value nil) 
  719.                   (go-to-instance nil) (go-to-type nil))
  720.              (cond
  721.               ((null selected-type)     (no-type-selected-handler))
  722.               ((null selected-instance) (no-instance-selected-handler t))
  723.               (T
  724.                (setf instance-structure (gets selected-type selected-instance))
  725.                ;; only be concerned with slots having plausible contents.
  726.                (setf slots->values
  727.                      (mapcan #'(lambda (s+a &aux value) (declare (cons s+a))
  728.                                 (setq value (funcall (cdr s+a) instance-structure))
  729.                                 (if (or (symbolp value) (listp value))
  730.                                   (list (cons (car s+a) value))))
  731.                              (slot-access selected-type)))
  732.                (setf selected-slot 
  733.                      (wind:menu-dialogue (mapcar #'car slots->values)
  734.                                          "Go To instance named in which slot of ~S?"
  735.                                          selected-instance))
  736.                (setf slot-value (cdr (assoc selected-slot slots->values)))
  737.                (setf go-to-instance
  738.                      (cond ((null slot-value)
  739.                             (ccl:ed-beep)
  740.                             (wind:message-dialogue "Slot ~A's value is NIL" selected-slot)
  741.                             nil)
  742.                            ((symbolp slot-value) slot-value)
  743.                            ;; only one choice
  744.                            ((and (listp slot-value) (null (cdr slot-value)))
  745.                             (car slot-value))
  746.                            ;; Must dive into list, and possibly sublists.
  747.                            ((listp slot-value)
  748.                             (let ((current-list slot-value) (current-selected nil))
  749.                               (loop
  750.                                 (setq current-selected
  751.                                       (wind:menu-dialogue 
  752.                                        current-list "Select an instance or sublist."))
  753.                                 (cond ((null current-selected)
  754.                                        (ccl:ed-beep)
  755.                                        (wind:message-dialogue 
  756.                                         "You have selected a NIL value.")
  757.                                        nil)
  758.                                        ((and (listp current-selected)
  759.                                             (cdr current-selected))
  760.                                        ;; Dotted pairs are pulled apart to list. This
  761.                                        ;; lets us do alists, but (a b . c) blows up.
  762.                                        (if (listp (cdr current-selected))
  763.                                          (setq current-list current-selected)
  764.                                          (setq current-list
  765.                                                (list (car current-selected)
  766.                                                      (cdr current-selected)))))
  767.                                       ((listp current-selected)
  768.                                        (return (car current-selected)))
  769.                                       (t (return current-selected))))))
  770.                            (T (ccl:ed-beep)
  771.                               (wind:message-dialogue
  772.                                "Selected slot must contain a symbol naming the instance to go to, or a list of instance names.")
  773.                               nil)))
  774.                (setf go-to-type
  775.                      (if (and go-to-instance (symbolp go-to-instance))
  776.                        (let ((candidate-types 
  777.                               (mapcan #'(lambda (st) 
  778.                                           (if (gets st go-to-instance) (list st)))
  779.                                       (ccl:ask type-menu
  780.                                                (ccl:table-sequence)))))
  781.                          (cond ((null candidate-types)
  782.                                 (ccl:ed-beep)
  783.                                 (wind:message-dialogue 
  784.                                  "~S is not the instance of any type!" go-to-instance)
  785.                                 nil)
  786.                                ((null (cdr candidate-types)) (car candidate-types))
  787.                                (t (wind:menu-dialogue 
  788.                                    candidate-types
  789.                                    "~S is an instance of multiple types; choose which:"
  790.                                    go-to-instance))))))
  791.                (when go-to-type
  792.                  ;; Update type selection.
  793.                (ccl:ask 
  794.                 type-menu
  795.                 (ccl:cell-deselect  (first (ccl:selected-cells)))
  796.                 (ccl:cell-select    (ccl:index-to-cell
  797.                                      (position go-to-type (ccl:table-sequence))))
  798.                 (ccl:scroll-to-cell (ccl:index-to-cell
  799.                                      (position go-to-type (ccl:table-sequence)))))
  800.                ;; Update instance selection and activate so it displays.
  801.                (ccl:ask
  802.                 instance-menu
  803.                 (ccl:cell-deselect (first (ccl:selected-cells)))
  804.                 (ccl:set-table-sequence (instances go-to-type))
  805.                 (ccl:cell-select (ccl:index-to-cell 
  806.                                   (position go-to-instance (ccl:table-sequence))))
  807.                 (ccl:scroll-to-cell (ccl:index-to-cell
  808.                                      (position go-to-instance (ccl:table-sequence))))
  809.                 (ccl:dialog-item-action)))))))))
  810.      
  811.      ;; Inspecting an instance or a type (if no instance selected).
  812.      (inspect-button
  813.       (ccl:oneof 
  814.        ccl:*button-dialog-item*
  815.        :dialog-item-text "Inspect"
  816.        :dialog-item-position (if small (ccl:make-point 353 161)
  817.                                  (ccl:make-point 530 61))
  818.        :dialog-item-enabled-p nil
  819.        :dialog-item-action
  820.        #'(lambda ()
  821.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  822.            (let ((selected-instance
  823.                   (ccl:ask instance-menu
  824.                            (if (ccl:selected-cells)
  825.                              (ccl:cell-contents (car (ccl:selected-cells))))))
  826.                  (selected-type
  827.                   (ccl:ask type-menu
  828.                            (if (ccl:selected-cells)
  829.                              (ccl:cell-contents (car (ccl:selected-cells)))))))
  830.              (cond 
  831.               ((null selected-type) (no-type-selected-handler))
  832.               ((null selected-instance) 
  833.                (inspect (get selected-type '$structure-type$)))
  834.               (T (inspect (sm:gets selected-type selected-instance))))))))
  835.  
  836.      ;; Changing the style by which instances are printed in the large browser.
  837.      (style-button
  838.       (ccl:oneof 
  839.        ccl:*button-dialog-item*
  840.        :dialog-item-text " Style "
  841.        :dialog-item-position (if small (ccl:make-point 357 136)
  842.                                  (ccl:make-point 534 36))
  843.        :dialog-item-enabled-p t
  844.        :dialog-item-action
  845.        #'(lambda ()
  846.            (setf *prints-style*
  847.                  (wind:menu-dialogue
  848.                   (if small 
  849.                     '(:name :brief :summary)
  850.                     '(:name :brief :summary :pretty :macro :pretty-macro))
  851.                   "Choose default printing style for this particular browser:")))))
  852.  
  853.      ;; Button for creating Fred window to edit a particular slot.
  854.      (sedit-button 
  855.       (ccl:oneof 
  856.        ccl:*button-dialog-item*
  857.        :dialog-item-text "Slot Edit"
  858.        :dialog-item-position (if small (ccl:make-point 352 36)
  859.                                  (ccl:make-point 458 36))
  860.        :dialog-item-enabled-p nil
  861.        :dialog-item-action
  862.        #'(lambda ()
  863.            (declare (object-variable (ccl:*dialog-item* ccl:my-dialog)))
  864.            (let ((selected-instance
  865.                   (ccl:ask instance-menu
  866.                            (if (ccl:selected-cells)
  867.                              (ccl:cell-contents (car (ccl:selected-cells))))))
  868.                  (selected-type
  869.                   (ccl:ask type-menu
  870.                            (if (ccl:selected-cells)
  871.                              (ccl:cell-contents (car (ccl:selected-cells)))))))
  872.              (cond 
  873.               ((null selected-type) (no-type-selected-handler))
  874.               ((null selected-instance) (no-instance-selected-handler T))
  875.               ((edit-slot selected-type selected-instance
  876.                           (wind:menu-dialogue
  877.                            (mapcar #'car (slot-access selected-type))
  878.                            "Edit which slot of ~A ~A?"
  879.                            selected-type selected-instance))))))))
  880.  
  881.      ;; Create the browser window itself, with unique name.  Dialog
  882.      ;; items must be listed in specified order for mutual reference.
  883.      (browser 
  884.       (ccl:oneof
  885.        ccl:*dialog*
  886.        :window-title (format nil "~A ~A" title (1+ (length *structure-browsers*)))
  887.        :window-position (if small (ccl:make-point 215 265)
  888.                             :centered)
  889.        :window-size (if small (ccl:make-point 420 208) 
  890.                         (ccl:make-point 605 325))
  891.        :window-type :tool
  892.        :dialog-items (list labels           ; first
  893.                            type-menu        ; second
  894.                            instance-menu    ; third
  895.                            display          ; fourth
  896.                            edit-button      ; fifth
  897.                            destroy-button   ; sixth
  898.                            copy-button      ; seventh
  899.                            new-button       ; eigth
  900.                            go-to-button     ; ninth
  901.                            inspect-button   ; tenth
  902.                            style-button     ; eleventh
  903.                            sedit-button)    ; twelth
  904.        :default-button nil)))
  905.     ;; save browser to be auto-destroyed when type info invalidated.
  906.     (push browser *structure-browsers*)
  907.     browser))
  908.  
  909. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  910. ;;;
  911. ;;;                            STRUCTURE EDITORS
  912. ;;;
  913. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  914.  
  915. (defun EDIT-TYPE (type)
  916.   "edit-type <type>                                                 [Function]
  917.   Given the symbolic names of a type, creates a Fred window holding the
  918.   DST expression that defines the type. This may be edited and evaluated
  919.   to change the type. If <type> is undefined, a null DST is given.  The
  920.   buffer also has a form to close all instance editor windows of instances
  921.   of the type, in case they become inconsistent. Returns the window,
  922.   immediately after window creation."
  923.   
  924.   ;; Error checking.
  925.   (check-type type symbol)
  926.   
  927.   (let ((*package* (if type (symbol-package type) (find-package "USER")))
  928.         (title (format nil "~A's Definition" 
  929.                        (if type (symbol-name type) "New Type")))
  930.         (dst-string "") (width 0) (height 0) (the-editor nil))
  931.     (declare (string dst-string) (fixnum width height))
  932.     
  933.     ;; Create the editor window, sized to fit the type definition.
  934.     (setf dst-string
  935.           (let ((*print-pretty* t) (*print-escape* t) (*print-circle* nil) 
  936.                 (*print-case* :downcase) (*print-array* t) 
  937.                 (ccl::*print-structure* t))
  938.             (if type 
  939.               (format nil
  940.                       ";;; Don't forget to specify whether to :redefine!~
  941.                        ~%(setf sm:*warn-of-redefinitions* t)~
  942.                        ~%(sm:dst ~A~{~&  ~S~})"
  943.                       (prin1-to-string (second (defining-form type)))
  944.                       (cddr (defining-form type)))
  945.  
  946.               ";;; A template for you to fill in:
  947. (sm:dst (<new-type> (:redefine nil) 
  948.                     (:reusable <t-or-nil>)
  949.                     (:sort-instances <t-or-nil>)
  950.                     (:before-edit (lambda (i) <actions on i>))
  951.                     (:after-edit (lambda (i) <actions on i>))
  952.                     (:after-load (lambda () <initialization actions>))
  953.                     (:comments <string>))
  954.   (<slot-name> <default> 
  955.                :type <slottype> 
  956.                :read-only <t-or-nil> 
  957.                :computed <t-or-nil> 
  958.                :comments <string>)
  959.   )")))
  960.     (multiple-value-bind 
  961.       (columns rows)
  962.       (wind:message-size dst-string)
  963.       (declare (integer columns rows))
  964.       (setf columns (max columns (+ 10 (length title))))
  965.       (setf width  (min 580 (max 350 (* 7 columns))))
  966.       (setf height 
  967.             (min 300
  968.                  (max 100
  969.                       (cond ((< rows 4)  (* (+ 4 *editor-window-font-height*)
  970.                                             rows))
  971.                             ((< rows 12) (* (+ 2 *editor-window-font-height*)
  972.                                             rows))
  973.                             (t (* *editor-window-font-height* rows)))))))
  974.  
  975.     (setf the-editor
  976.           (ccl:oneof ccl:*fred-window*
  977.                      :window-title title
  978.                      :window-position (next-window-position width height)
  979.                      :window-size (ccl:make-point width height)
  980.                      :window-show t
  981.                      :window-font *editor-window-font*
  982.                      :window-type :document-with-zoom
  983.                      :close-box-p t
  984.                      :scratch-p nil ; trouble.
  985.                      :package *package*))
  986.     ;; Insert the macro representation, and expression to close instance windows.
  987.     (ccl:buffer-insert (ccl:ask the-editor (ccl:window-buffer)) dst-string)
  988.     (if type 
  989.       (ccl:buffer-insert (ccl:ask the-editor (ccl:window-buffer))
  990.                          (format nil 
  991.                                  "~%(sm:destroy-sm-editor-windows-of-type '~S)~
  992.                                   ~%(setf (get '~S 'sm::$browser-doc-string$) nil)"
  993.                                  type type)))
  994.     (ccl:ask the-editor (ccl:window-update))
  995.  
  996.     ;; Return result.
  997.     the-editor))
  998.  
  999. (defun EDITS (type instance &key (omit nil))
  1000.   "edits <type> <instance> &key :omit                            [Function]
  1001.   Given the symbolic names of a type and an instance of the type,
  1002.   creates a Fred window holding the pretty-macro printed version of
  1003.   the instance.  This may be edited and evaluated to change the 
  1004.   instance.  It is an error if the type is not defined, but undefined
  1005.   instances are defined automatically with default slot contents.
  1006.   Returns the window, immediately after window creation."
  1007.   
  1008.   ;; Error checking and instance creation.
  1009.   (check-type type symbol)
  1010.   (check-type instance symbol)
  1011.   (check-type omit list)
  1012.   (assert (member type (structure-types)) (type)
  1013.           "Structure type ~S is not defined." type)
  1014.  
  1015.   (if (not (member instance (instances type)))
  1016.     (funcall (creator type) instance))
  1017.   
  1018.   (let* ((*package*
  1019.           ;; Edit in package specified, or default to package of instance name,
  1020.           ;; unless it is keyword package, in which case we use type's package.
  1021.           (or (find-package (type-info type :edit-in-package))
  1022.               (let ((ipkg (symbol-package instance)))
  1023.                 (if (eq ipkg *keyword-package*) (symbol-package type) ipkg))))
  1024.          (title (prints type instance :style :name :stream nil))
  1025.          (the-editor (find-editor-window title))
  1026.          (struct-string "") (width 0) (height 0))
  1027.     (declare (string title struct-string) (fixnum width height))
  1028.     
  1029.     (cond (the-editor
  1030.            
  1031.            ;; Window exists: just activate.
  1032.            (ccl:ask the-editor (ccl:window-select)))
  1033.           
  1034.           ;; None yet: Create the editor window, sized to fit the macro
  1035.           ;; representation, with the correct package.
  1036.           (t
  1037.            (setf struct-string
  1038.                  (prints type instance 
  1039.                          :style :pretty-macro :omit omit :stream nil))
  1040.            (multiple-value-bind 
  1041.              (columns rows)
  1042.              (wind:message-size struct-string)
  1043.              (declare (integer columns rows))
  1044.              (setf columns (max columns (+ 10 (length title))))
  1045.              (setf width  (min 580 (max 250 (* 7 columns))))
  1046.              (setf height 
  1047.                    (min 300
  1048.                         (max 100
  1049.                              (cond ((< rows 4)  (* (+ 4 *editor-window-font-height*)
  1050.                                                    rows))
  1051.                                    ((< rows 12) (* (+ 2 *editor-window-font-height*)
  1052.                                                    rows))
  1053.                                    (t (* *editor-window-font-height* rows)))))))
  1054.            (setf the-editor
  1055.                  (ccl:oneof ccl:*fred-window*
  1056.                             :window-title title
  1057.                             :window-position (next-window-position width height)
  1058.                             :window-size (ccl:make-point width height)
  1059.                             :window-show t
  1060.                             :window-font *editor-window-font*
  1061.                             :window-type :document-with-zoom
  1062.                             :close-box-p t
  1063.                             :scratch-p nil
  1064.                             :package *package*))
  1065.            ;; Insert call to any additional actions needed before editing.
  1066.            (let ((action (type-info type :before-edit)))
  1067.              (when action 
  1068.                (ccl:buffer-insert 
  1069.                 (ccl:ask the-editor (ccl:window-buffer))
  1070.                 (let ((*print-pretty* t))
  1071.                   (format nil ";---------- :before-edit actions: ---------~
  1072.                                ~%(FUNCALL ~%  '~A ~%  '~S)~
  1073.                                ~%;------------------------------------------~%"
  1074.                           (prin1-to-string action) instance)))
  1075.                ;; Scroll the window past this garbage.
  1076.                (ccl:ask the-editor 
  1077.                         (ccl:set-mark (ccl:window-start-mark) 
  1078.                                       (ccl:buffer-mark 
  1079.                                        (ccl:ask the-editor (ccl:window-buffer)))))))
  1080.            ;; Insert the macro representation.
  1081.            (ccl:buffer-insert (ccl:ask the-editor (ccl:window-buffer)) struct-string)
  1082.            ;; Insert call to any additional actions needed after editing.
  1083.            (let ((action (type-info type :after-edit)))
  1084.              (if action 
  1085.                (ccl:buffer-insert
  1086.                 (ccl:ask the-editor (ccl:window-buffer))
  1087.                 (let ((*print-pretty* t))
  1088.                   (format nil "~%;---------- :after-edit actions: ----------~
  1089.                                ~%(FUNCALL ~%  '~A ~%  '~S)"
  1090.                           (prin1-to-string action) instance)))))
  1091.            (ccl:ask the-editor (ccl:window-update))
  1092.            ;; Record the window under the type, for auto-destroying. (Why don't I
  1093.            ;; use info slot here? Because the user may clobber it!)
  1094.            (push the-editor (get type '$SM-editor-windows$))))
  1095.  
  1096.     ;; Return result.
  1097.     the-editor))
  1098.  
  1099. (defun EDIT-SLOT (type instance slot)
  1100.   "edit-slot <type> <instance> slot                                [Function]
  1101.   Given the names of a type, an instance of the type, and a slot, creates
  1102.   a Fred window holding a SETF expression which when evaluated will set
  1103.   the contents of the slot to its current value (which may be edited).
  1104.   Returns the window, immediately after window creation."
  1105.   
  1106.   ;; Error checking and instance creation.
  1107.   (check-type type symbol)
  1108.   (check-type instance symbol)
  1109.   (check-type slot symbol)
  1110.   (assert (member type (structure-types)) (type)
  1111.           "Structure type ~S is not defined." type)
  1112.   (assert (assoc slot (slot-access type)) (slot type)
  1113.           "Slot ~S is not defined for type ~S." slot type)
  1114.   (assert (sm:gets type instance) (instance type)
  1115.           "Instance ~S of type ~S does not exist." instance type)
  1116.   
  1117.   (let* ((*package* (symbol-package instance))
  1118.          (title (format nil "~S-~S of ~S" type slot instance))
  1119.          (slot-string "") (width 0) (height 0) (the-editor nil))
  1120.     (declare (string title slot-string) (fixnum width height))
  1121.     
  1122.     ;; Create the editor window, sized to fit the setf expression.
  1123.     (setf slot-string
  1124.           (let ((*print-pretty* T) (*print-escape* t) (*print-circle* nil) 
  1125.                  (*print-case* :upcase) (*print-array* t) 
  1126.                  (ccl::*print-structure* t)
  1127.                  (slot-contents 
  1128.                   (funcall (cdr (assoc slot (slot-access type)))
  1129.                            (sm:gets type instance))))
  1130.             (format nil "(setf (~S-~A (sm:gets '~S '~S))~%'~A)"
  1131.                     type slot type instance
  1132.                     (prin1-to-string slot-contents))))
  1133.     
  1134.     (multiple-value-bind 
  1135.       (columns rows)
  1136.       (wind:message-size slot-string)
  1137.       (declare (integer columns rows))
  1138.       (setf columns (max columns (+ 10 (length title))))
  1139.       (setf width  (min 580 (max 250 (* 7 columns))))
  1140.       (setf height 
  1141.             (min 300
  1142.                   (max 100
  1143.                          (cond ((< rows 4)  (* (+ 4 *editor-window-font-height*)
  1144.                                                   rows))
  1145.                                   ((< rows 12) (* (+ 2 *editor-window-font-height*)
  1146.                                                       rows))
  1147.                                   (t (* *editor-window-font-height* rows)))))))
  1148.     (setf the-editor
  1149.           (ccl:oneof ccl:*fred-window*
  1150.                       :window-title title
  1151.                       :window-position (next-window-position width height)
  1152.                       :window-size (ccl:make-point width height)
  1153.                       :window-show t
  1154.                       :window-font *editor-window-font*
  1155.                       :window-type :document-with-zoom
  1156.                       :close-box-p t
  1157.                       :scratch-p t
  1158.                       :package *package*))
  1159.     ;; Insert the setf form.
  1160.     (ccl:buffer-insert (ccl:ask the-editor (ccl:window-buffer)) slot-string)
  1161.     (ccl:ask the-editor (ccl:window-update))
  1162.     ;; Record the window under the type, for auto-destroying.
  1163.     (push the-editor (get type '$SM-editor-windows$))
  1164.     
  1165.     ;; Return result.
  1166.     the-editor))
  1167.  
  1168. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1169. ;;;
  1170. ;;;                          HELPER FUNCTIONS
  1171. ;;;
  1172. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1173.  
  1174. (defun FIND-EDITOR-WINDOW (title)
  1175.   (dolist (fred-window (ccl:windows ccl:*fred-window*))
  1176.     (if (string= title (ccl:ask fred-window (ccl:window-title)))
  1177.       (return-from find-editor-window fred-window))))
  1178.  
  1179. ;;; Generate new name interactively with user.
  1180.  
  1181. (defun NEW-INSTANCE-NAME (type &aux (name nil))
  1182.   "Given the name of a structure type, interactively gets a new 
  1183.   instance name from the user, with suggested default a name 
  1184.   created by gensym using the type name as prefix.  Returns the
  1185.   symbol, or NIL if there is an error or cancel."
  1186.   (check-type type symbol)
  1187.   (assert (member type (structure-types)) (type) "Unknown type.")
  1188.   (catch :cancel ; for CCL but won't hurt otherwise
  1189.     (let ((*package* (symbol-package type))) ; read in same package
  1190.       (setf name 
  1191.             (read-from-string
  1192.              (wind:get-string-default-dialogue
  1193.               (symbol-name (utils:unique-symbol 
  1194.                             (concatenate 'string (symbol-name type) "-")))
  1195.               "Enter name of the new instance of type ~A:" type)
  1196.              nil :eof$))))
  1197.   (cond ((or (not (symbolp name)) (eq name :eof$))
  1198.          (wind:message-dialogue "Error in reading your input as a symbol.")
  1199.          (new-instance-name type))
  1200.         ((member name (instances type))
  1201.          (wind:message-dialogue "That name is already in use for ~A." type)
  1202.          (new-instance-name type))
  1203.         (name)))
  1204.  
  1205. (defvar *POPUP-POSITIONS*
  1206.   (let ((positions (list
  1207.                     ;; Each element consists of a window position and two integers
  1208.                     ;; which are the H and V upper bounds for window sizes using
  1209.                     ;; the given position.
  1210.                     (list (ccl:make-point 10 40)      ; NOTE: change next-window-position
  1211.                           (- ccl:*screen-width* 20)   ; if changing these smallest values,
  1212.                           (- ccl:*screen-height* 50)) ; to prevent infinite loop.
  1213.                     (list (ccl:make-point 20 60)
  1214.                           (- ccl:*screen-width* 30) 
  1215.                           (- ccl:*screen-height* 70))
  1216.                     (list (ccl:make-point 30 80) 
  1217.                           (- ccl:*screen-width* 40) 
  1218.                           (- ccl:*screen-height* 90))
  1219.                     (list (ccl:make-point 40 100)
  1220.                           (- ccl:*screen-width* 50) 
  1221.                           (- ccl:*screen-height* 110))
  1222.                     (list (ccl:make-point 50 120)
  1223.                           (- ccl:*screen-width* 60) 
  1224.                           (- ccl:*screen-height* 130))
  1225.                     (list (ccl:make-point 60 140)
  1226.                           (- ccl:*screen-width* 70) 
  1227.                           (- ccl:*screen-height* 150))
  1228.                     (list (ccl:make-point 70 160)
  1229.                           (- ccl:*screen-width* 80) 
  1230.                           (- ccl:*screen-height* 170))
  1231.                     (list (ccl:make-point 80 180)
  1232.                           (- ccl:*screen-width* 90)
  1233.                           (- ccl:*screen-height* 190))
  1234.                     (list (ccl:make-point 90 200)
  1235.                           (- ccl:*screen-width* 100) 
  1236.                           (- ccl:*screen-height* 210)))))
  1237.     (setf (cdr (last positions)) positions))
  1238.   "A CIRCULAR list of nicely overlapping popup positions.")
  1239.  
  1240. (defun NEXT-WINDOW-POSITION (width height &aux pos-list)
  1241.   "Given the width and height of a window, returns a position at
  1242.   which the window may be placed which overlaps nicely with 
  1243.   previous windows placed using this function, and is guaranteed
  1244.   to keep the window entirely on the screen, provided it is small enough."
  1245.   (check-type width integer)
  1246.   (check-type height integer)
  1247.   ;; The following is necessary to prevent infinite loops on big windows.
  1248.   (if (or (> width (- ccl:*screen-width* 20))
  1249.           (> height (- ccl:*screen-height* 50)))
  1250.     (ccl:make-point 5 ccl:*menubar-bottom*)
  1251.     (loop
  1252.       (setf pos-list (pop *popup-positions*))
  1253.       (if (and (<= width (second pos-list))
  1254.                (<= height (third pos-list)))
  1255.         (return (first pos-list))))))
  1256.  
  1257. (defun DESTROY-STRUCTURE-BROWSERS ()
  1258.   (loop
  1259.     (if (null *structure-browsers*) (return))
  1260.     ;; Coral manual says to check wptr binding to see if the
  1261.     ;; user has already closed it.
  1262.     (ccl:ask (pop *structure-browsers*)
  1263.              (if (boundp 'ccl:wptr) (ccl:window-close)))))
  1264.  
  1265. (defun DESTROY-SM-EDITOR-WINDOWS-OF-TYPE (type &key (ask-user nil))
  1266.   (loop
  1267.     (if (null (get type '$SM-editor-windows$)) (return))
  1268.     (ccl:ask (pop (get type '$SM-editor-windows$))
  1269.              (if (boundp 'ccl:wptr)
  1270.                (if ask-user 
  1271.                  (ccl:window-close)
  1272.                  ;; Trick to bypass the Fred window save-to-file dialogs.
  1273.                  (funcall (ccl:ask ccl:*window* 
  1274.                                    (symbol-function 'ccl:window-close))))))))
  1275.  
  1276. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1277. ;;;
  1278. ;;;                                MENU
  1279. ;;;
  1280. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1281.  
  1282. (defun SAVE-TYPE-PARAMETER-DIALOGUE (type)
  1283.   "save-type-parameter-dialogue <type>                              [Function]
  1284.   Returns 4 values, each being T or Nil, indicating whether to compile 
  1285.   the file, whether to write the DST type definition to the file, whether
  1286.   to let the user select which instances to save, and whether to append 
  1287.   to an existing file instead of writing a new one."
  1288.   (let* 
  1289.     ((compile-checkbox
  1290.       (ccl:oneof ccl:*check-box-dialog-item*
  1291.                  :dialog-item-text "Compile File"
  1292.                  :dialog-item-position (ccl:make-point 9 40)
  1293.                  :dialog-item-size (ccl:make-point 99 16)
  1294.                  :check-box-checked-p nil))
  1295.      (typedef-checkbox
  1296.       (ccl:oneof ccl:*check-box-dialog-item*
  1297.                  :dialog-item-text "Include Type Definition"
  1298.                  :dialog-item-position (ccl:make-point 9 68)
  1299.                  :dialog-item-size (ccl:make-point 171 16)
  1300.                  :check-box-checked-p (type-info type :save-type-definition)))
  1301.      (select-checkbox 
  1302.       (ccl:oneof ccl:*check-box-dialog-item*
  1303.                  :dialog-item-text "Save Selected Instances"
  1304.                  :dialog-item-position (ccl:make-point 9 96)
  1305.                  :dialog-item-size (ccl:make-point 180 16)
  1306.                  :check-box-checked-p nil))
  1307.      (append-checkbox 
  1308.       (ccl:oneof ccl:*check-box-dialog-item*
  1309.                  :dialog-item-text "Append to Existing File"
  1310.                  :dialog-item-position (ccl:make-point 9 124)
  1311.                  :dialog-item-size (ccl:make-point 180 16)
  1312.                  :check-box-checked-p nil))
  1313.      (static-label
  1314.       (ccl:oneof ccl:*static-text-dialog-item*
  1315.                  :dialog-item-text (format nil "Parameters for saving ~A:" type)
  1316.                  :dialog-item-position (ccl:make-point 9 9)
  1317.                  :dialog-item-size (ccl:make-point 280 16)))
  1318.      (ok-button
  1319.       (ccl:oneof ccl:*button-dialog-item*
  1320.                  :dialog-item-text " OK "
  1321.                  :dialog-item-position (ccl:make-point 243 48)
  1322.                  :dialog-item-size (ccl:make-point 35 16)
  1323.                  :dialog-item-action 
  1324.                  #'(lambda () 
  1325.                      (ccl:return-from-modal-dialog
  1326.                       (values (ccl:ask compile-checkbox (ccl:check-box-checked-p))
  1327.                               (ccl:ask typedef-checkbox (ccl:check-box-checked-p))
  1328.                               (ccl:ask select-checkbox (ccl:check-box-checked-p))
  1329.                               (ccl:ask append-checkbox (ccl:check-box-checked-p)))))
  1330.                  :default-button t))
  1331.      (cancel-button
  1332.       (ccl:oneof ccl:*button-dialog-item*
  1333.                  :dialog-item-text "Cancel"
  1334.                  :dialog-item-position (ccl:make-point 235 83)
  1335.                  :dialog-item-size (ccl:make-point 53 16)
  1336.                  :dialog-item-action
  1337.                  #'(lambda () (ccl:return-from-modal-dialog :cancel))))
  1338.      (the-dialog
  1339.       (ccl:oneof ccl:*dialog*
  1340.                  :window-title "Save Type Dialog"
  1341.                  :window-position :centered
  1342.                  :window-size (ccl:make-point 300 150)
  1343.                  :window-type :double-edge-box
  1344.                  :dialog-items (list static-label 
  1345.                                      compile-checkbox
  1346.                                      typedef-checkbox
  1347.                                      select-checkbox
  1348.                                      append-checkbox
  1349.                                      ok-button cancel-button))))
  1350.     (ccl:modal-dialog the-dialog)))
  1351.  
  1352. (defparameter *SM-menu*
  1353.   (let* ((line-item
  1354.           (ccl:oneof ccl:*menu-item* :menu-item-title "-"))
  1355.          (browse-item 
  1356.           (ccl:oneof
  1357.            ccl:*menu-item*
  1358.            :menu-item-title "SM Structure Browser..."
  1359.            :menu-item-action 
  1360.            #'(lambda ()
  1361.                (browse-structs :small (wind:y-or-n-dialogue "Make Small browser?")))))
  1362.          (warn-item
  1363.           (ccl:oneof
  1364.            ccl:*menu-item*
  1365.            :menu-item-title "Warn of Redefinitions"
  1366.            :menu-item-action 
  1367.            '(progn (setf *warn-of-redefinitions*
  1368.                          (not *warn-of-redefinitions*))
  1369.              (if *warn-of-redefinitions*
  1370.                (ccl:set-menu-item-check-mark t)
  1371.                (ccl:set-menu-item-check-mark nil)))))
  1372.          
  1373.          (close-type-windows-item
  1374.           (ccl:oneof 
  1375.            ccl:*menu-item*
  1376.            :menu-item-title "Close Windows of Type ..."
  1377.            :menu-item-action
  1378.            #'(lambda ()
  1379.                (dolist (type 
  1380.                         (wind:multiple-menu-dialogue
  1381.                          (sm:structure-types)
  1382.                          "Destroy all Fred windows containing instances of which types?"))
  1383.                  (destroy-sm-editor-windows-of-type type)))))
  1384.  
  1385.          (edit-type-item
  1386.           (ccl:oneof 
  1387.            ccl:*menu-item*
  1388.            :menu-item-title "Edit Type Definition ..."
  1389.            :menu-item-action
  1390.            #'(lambda ()
  1391.                (let ((type 
  1392.                       (wind:menu-dialogue 
  1393.                        (cons '|Make New Type| (structure-types))
  1394.                        "Edit Definition of which Structure Type?")))
  1395.                  (if (eq type '|Make New Type|)
  1396.                    (edit-type nil)
  1397.                    (edit-type type))))))
  1398.  
  1399.          (reset-type-item 
  1400.           (ccl:oneof
  1401.            ccl:*menu-item*
  1402.            :menu-item-title "Reset Structure Type..."
  1403.            :menu-item-action 
  1404.            #'(lambda ()
  1405.                (let ((type 
  1406.                       (wind:menu-dialogue 
  1407.                        (structure-types) 
  1408.                        "Reset (destroy all instances of) which Structure Type?")))
  1409.                  (reset-type type)
  1410.                  (destroy-structure-browsers)))))
  1411.          (destroy-type-item
  1412.           (ccl:oneof 
  1413.            ccl:*menu-item*
  1414.            :menu-item-title "Destroy Structure Type..."
  1415.            :menu-item-action 
  1416.            #'(lambda ()
  1417.                (let ((type 
  1418.                       (wind:menu-dialogue
  1419.                        (structure-types)
  1420.                        "Destroy (destroy all instances of and undefine) which Structure Type?")))
  1421.                  (destroy-type type)
  1422.                  (setf (get type '$browser-doc-string$) nil)
  1423.                  (destroy-SM-editor-windows-of-type type)
  1424.                  (destroy-structure-browsers)))))
  1425.          (freelist-item
  1426.           (ccl:oneof 
  1427.            ccl:*menu-item*
  1428.            :menu-item-title "Freelist Manager..."
  1429.            :menu-item-action 
  1430.            #'(lambda ()
  1431.                (let ((types-with-freelists
  1432.                       (mapcan #'(lambda (type) (if (freelist type) (list type)))
  1433.                               (structure-types))))
  1434.                  (if types-with-freelists
  1435.                    (let ((type 
  1436.                           (wind:menu-dialogue
  1437.                            types-with-freelists
  1438.                            "The following Structure Types have nonempty Freelists (containing reusable allocated structures).  Select one to see its length (with option of flushing), or cancel:")))
  1439.                      (when (wind:y-or-n-dialogue
  1440.                             "Type ~S has ~S reusable instances on its Freelist.  Do you want to reclaim (gc) them?"
  1441.                             type (length (freelist type)))
  1442.                        (flush-freelist type)
  1443.                        (ccl:gc)))
  1444.                    (wind:message-dialogue 
  1445.                     "No structure type currently has structures allocated on its freelist."))))))
  1446.          (reset-SM-item 
  1447.           (ccl:oneof 
  1448.            ccl:*menu-item*
  1449.            :menu-item-title "Reset SM..."
  1450.            :menu-item-action 
  1451.            #'(lambda ()
  1452.                (if (wind:y-or-n-dialogue 
  1453.                     "Reset (destroy all instances of) ALL SM Structure types?")
  1454.                  (progn
  1455.                    (reset-all-types)
  1456.                    (destroy-structure-browsers))))))
  1457.          (destroy-SM-item 
  1458.           (ccl:oneof
  1459.            ccl:*menu-item*
  1460.            :menu-item-title "Destroy SM..."
  1461.            :menu-item-action 
  1462.            #'(lambda ()
  1463.                (if (wind:y-or-n-dialogue 
  1464.                     "Destroy (destroy all instances of and undefine) ALL SM Structure types?")
  1465.                  (progn
  1466.                    (dolist (type (structure-types))
  1467.                      (setf (get type '$browser-doc-string$) nil)
  1468.                      (destroy-SM-editor-windows-of-type type))
  1469.                    (destroy-all-types)
  1470.                    (destroy-structure-browsers))))))
  1471.          
  1472.          ;; In the next two, we construct paths even though the functions called
  1473.          ;; do the same, since we can use macintosh file dialogues here.
  1474.          
  1475.          (load-type-item
  1476.           (ccl:oneof 
  1477.            ccl:*menu-item*
  1478.            :menu-item-title "Load Structure Type..."
  1479.            :menu-item-action
  1480.            #'(lambda ()
  1481.                (let* ((type 
  1482.                        (wind:menu-dialogue
  1483.                         (cons "New Type" (structure-types))
  1484.                         "Load from disk instances of which Structure Type?"))
  1485.                       (file-path nil))
  1486.                  (if (equal type "New Type")
  1487.                    (setq type
  1488.                          (read-from-string
  1489.                           (wind:get-string-dialogue 
  1490.                            "Enter the name of the type, including package. ~
  1491.                            (The type must be defined by the file loaded.)"))))
  1492.                  (setq file-path
  1493.                        (ccl:choose-file-dialog
  1494.                         :directory
  1495.                         (format nil "~A~A.~A"
  1496.                                 *default-instance-file-path*
  1497.                                 type
  1498.                                 *default-instance-file-type*)))
  1499.                  (if (probe-file file-path)
  1500.                    (progn
  1501.                      ;; Change default path to one given, and record path
  1502.                      (setf *default-instance-file-path*
  1503.                            (directory-namestring file-path))
  1504.                      (ccl:eval-enqueue 
  1505.                       `(load-type ',type :path ',file-path)))
  1506.                    (wind:message-dialogue 
  1507.                     "File ~S doesn't seem to exist." (namestring file-path)))))))
  1508.          (save-type-item
  1509.           (ccl:oneof
  1510.            ccl:*menu-item*
  1511.            :menu-item-title "Save Structure Type..."
  1512.            :menu-item-action 
  1513.            #'(lambda ()
  1514.                (let* 
  1515.                  ((type 
  1516.                    (wind:menu-dialogue
  1517.                     (structure-types) 
  1518.                     "Save to disk instances of which Structure Type?"))
  1519.                   (file-path
  1520.                    (pathname 
  1521.                     (ccl:choose-new-file-dialog
  1522.                      ;; Pathname defaults first to that loaded
  1523.                      ;; from, second to file with name of type
  1524.                      ;; in path last used for instance access.
  1525.                      :directory
  1526.                      (let ((prev-path (get type '$SM-instance-path$)))
  1527.                        (if prev-path
  1528.                          (make-pathname 
  1529.                           :device    (pathname-device prev-path)
  1530.                           :directory (pathname-directory prev-path)
  1531.                           :name      (pathname-name prev-path)
  1532.                           :type      *default-instance-file-type*)
  1533.                          (make-pathname
  1534.                           :directory *default-instance-file-path*
  1535.                           :name (symbol-name type)
  1536.                           :type      *default-instance-file-type*)))
  1537.                      :prompt 
  1538.                      (format nil "Save ~A to ..." type))))
  1539.                   (backup-path
  1540.                    (make-pathname
  1541.                     :host      (pathname-host file-path)
  1542.                     :device    (pathname-device file-path)
  1543.                     :directory (pathname-directory file-path)
  1544.                     :name      (pathname-name file-path)
  1545.                     :type      "bak"))
  1546.                   (instances (instances type)))
  1547.                  (multiple-value-bind
  1548.                    (compile-p define-type-p specify-instances append-p)
  1549.                    (save-type-parameter-dialogue type)
  1550.                    (if specify-instances
  1551.                      (setf instances
  1552.                            (wind:multiple-menu-dialogue
  1553.                             instances
  1554.                             "Choose the instances of ~S to save to ~S"
  1555.                             type (namestring file-path))))
  1556.                    (when (and (not append-p) (probe-file file-path))
  1557.                      (if (probe-file backup-path) (delete-file backup-path))
  1558.                      (rename-file file-path backup-path)
  1559.                      (format T "~&;~A backed up to ~A" 
  1560.                              (namestring file-path) (namestring backup-path)))
  1561.                    (setf *default-instance-file-path* 
  1562.                          (directory-namestring file-path))
  1563.                    ;; Eval-enqueue of save-type dangerous, but compile can be.
  1564.                    (save-type type
  1565.                               :path file-path
  1566.                               :style :pretty-macro
  1567.                               :compile nil
  1568.                               :define-type define-type-p
  1569.                               :instances instances
  1570.                               :append append-p)
  1571.                    (format T "~&;Instances of ~A saved to ~S"
  1572.                            type (namestring file-path))
  1573.                    ;; Editor windows are marked as modified.  Destroying them when
  1574.                    ;; all is done "unlocks" exit from lisp.  (I am trying to make the
  1575.                    ;; presence of modified sm:edits windows the indicator that there
  1576.                    ;; is in-memory stuff to be saved.  To encourage the user to take
  1577.                    ;; them as such, I try to be consistent and destroy them when there
  1578.                    ;; is nothing to be saved.)
  1579.                    (ccl:eval-enqueue 
  1580.                     `(progn
  1581.                        (when ',compile-p 
  1582.                          (compile-file ,(namestring file-path)))
  1583.                        (unless ',specify-instances 
  1584.                          (destroy-sm-editor-windows-of-type ',type)))))))))
  1585.  
  1586.          (dispose-item
  1587.           (ccl:oneof 
  1588.            ccl:*menu-item*
  1589.            :menu-item-title "Hide This Menu"
  1590.            :menu-item-action 
  1591.            '(ccl:ask *SM-menu* (ccl:menu-deinstall))))
  1592.  
  1593.          (SM-menu (ccl:oneof ccl:*menu* 
  1594.                              :menu-title "SM"
  1595.                              :menu-items (list browse-item
  1596.                                                warn-item
  1597.                                                close-type-windows-item
  1598.                                                line-item
  1599.                                                edit-type-item
  1600.                                                reset-type-item
  1601.                                                destroy-type-item
  1602.                                                freelist-item
  1603.                                                line-item
  1604.                                                load-type-item
  1605.                                                save-type-item
  1606.                                                line-item
  1607.                                                reset-SM-item
  1608.                                                destroy-SM-item
  1609.                                                line-item
  1610.                                                dispose-item))))
  1611.     (ccl:defobfun (ccl:menu-item-update warn-item) ()
  1612.                   (if *warn-of-redefinitions*
  1613.                     (ccl:set-menu-item-check-mark t)
  1614.                     (ccl:set-menu-item-check-mark nil)))
  1615.     (ccl:ask SM-menu (ccl:menu-install))
  1616.     (ccl:ask line-item (ccl:menu-item-disable))
  1617.     ;; 1.3.1 dumped menu-dispose?
  1618.     (if (and (boundp '*sm-menu*) 
  1619.              (typep *sm-menu* ccl:*menu*))
  1620.       (ccl:ask *sm-menu* (ccl:menu-deinstall)))
  1621.     SM-menu))
  1622.  
  1623. (ccl:ask ccl:*tools-menu*
  1624.   (ccl:add-menu-items
  1625.    (ccl:oneof ccl:*menu-item*
  1626.           :menu-item-title "Restore SM Menu"
  1627.           :menu-item-action
  1628.           #'(lambda ()
  1629.               (ccl:ask *sm-menu*
  1630.                 (unless (ccl:menu-installed-p) (ccl:menu-install)))))))
  1631.  
  1632. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1633. (provide :SMEDIT)
  1634. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1635. ;;; EOF